// http://pdc.ro.nu/hamming.html

#include <stdio.h>
#include <stdlib.h>

void printbin(bool * bitarray);
void char2bin(unsigned char number, bool * bitarray);
char bin2char(bool * bitarray);
void encode(unsigned char number, bool * bitarray1, bool * bitarray2);
bool decode(unsigned char * number, bool * bitarray1, bool * bitarray2);

void main() {
    unsigned char number;
    bool bitarray[8];
    bool bitarray1[8];
    bool bitarray2[8];
    bool check, totalCheck=1;

   // for(int i=0; i<256; i++) {
        number = 16;
        char2bin(number, bitarray);
        number = bin2char(bitarray);
        //printf("%i, ", number);
        //printbin(bitarray);

        encode(number, bitarray1, bitarray2);
                
        // Fake error
        //bitarray1[0] = !bitarray1[0];
        //bitarray2[3] = !bitarray2[3];
        //bitarray2[0] = 0;

        printbin(bitarray1);
        printbin(bitarray2);

        check = decode(&number, bitarray1, bitarray2);

        printf("%i, ", number);
        char2bin(number, bitarray);
        printbin(bitarray);
        //printf("%s\n\n", check?"Klopt":"Klopt niet");

        if(!check) {
            totalCheck = 0;
        }
    //}
    printf("%s\n\n", totalCheck?"Alles klopt":"Niet alles klopt");
    system("pause");
}

void printbin(bool * bitarray) {
    printf("%i%i%i%i%i%i%i%i\n", bitarray[7]?1:0, bitarray[6]?1:0, bitarray[5]?1:0, bitarray[4]?1:0, bitarray[3]?1:0, bitarray[2]?1:0, bitarray[1]?1:0, bitarray[0]?1:0);
}

void char2bin(unsigned char number, bool * bitarray) {
    for (int j=0; j<8; j++) {
        bitarray[j] = ((number >> j) & 1);
    }
}

char bin2char(bool * bitarray) {
    char number = 0;

    for(int i=0; i<8; i++) {
        if(bitarray[i]) {
            number += 1<<i;
        }
    }
    return number;
}

void encode(unsigned char number, bool * bitarray1, bool * bitarray2) {
    //b3, b3^b2^b1, b2, !b2^b1^b0, b1, !b3^b1^b0, b0, !b3^b2^b0
    bool bitarray[8];
    char2bin(number, bitarray);

    bitarray1[7] = bitarray[3];
    bitarray1[6] = bitarray[3]^bitarray[2]^bitarray[1];
    bitarray1[5] = bitarray[2];
    bitarray1[4] = !bitarray[2]^bitarray[1]^bitarray[0];
    bitarray1[3] = bitarray[1];
    bitarray1[2] = !bitarray[3]^bitarray[1]^bitarray[0];
    bitarray1[1] = bitarray[0];
    bitarray1[0] = !bitarray[3]^bitarray[2]^bitarray[0];

    bitarray2[7] = bitarray[7];
    bitarray2[6] = bitarray[7]^bitarray[6]^bitarray[5];
    bitarray2[5] = bitarray[6];
    bitarray2[4] = !bitarray[6]^bitarray[5]^bitarray[4];
    bitarray2[3] = bitarray[5];
    bitarray2[2] = !bitarray[7]^bitarray[5]^bitarray[4];
    bitarray2[1] = bitarray[4];
    bitarray2[0] = !bitarray[7]^bitarray[6]^bitarray[4];
}

bool decode(unsigned char * number, bool * bitarray1, bool * bitarray2) {
    //    p  = h7 ^ h6 ^ h5 ^ h4 ^ h3 ^ h2 ^ h1 ^ h0
    //    c0 = h7 ^ h5 ^ h1 ^ h0
    //    c1 = h7 ^ h3 ^ h2 ^ h1
    //    c2 = h5 ^ h4 ^ h3 ^ h1
    bool bitarray[8];
    bool p1, p2, c01, c02, c11, c12, c21, c22;
    
    p1  = bitarray1[7] ^ bitarray1[6] ^ bitarray1[5] ^ bitarray1[4] ^ bitarray1[3] ^ bitarray1[2] ^ bitarray1[1] ^ bitarray1[0];
    c01 = bitarray1[7] ^ bitarray1[5] ^ bitarray1[1] ^ bitarray1[0];
    c11 = bitarray1[7] ^ bitarray1[3] ^ bitarray1[2] ^ bitarray1[1];
    c21 = bitarray1[5] ^ bitarray1[4] ^ bitarray1[3] ^ bitarray1[1];

    p2  = bitarray2[7] ^ bitarray2[6] ^ bitarray2[5] ^ bitarray2[4] ^ bitarray2[3] ^ bitarray2[2] ^ bitarray2[1] ^ bitarray2[0];
    c02 = bitarray2[7] ^ bitarray2[5] ^ bitarray2[1] ^ bitarray2[0];
    c12 = bitarray2[7] ^ bitarray2[3] ^ bitarray2[2] ^ bitarray2[1];
    c22 = bitarray2[5] ^ bitarray2[4] ^ bitarray2[3] ^ bitarray2[1];

    // If the parity, p, is correct (equal to 1) then either 0 or 2 errors occurred. If all the check bits, c0, c1, c2 are correct (equal to 1) then the byte was received intact, (no errors) otherwise it was damaged beyond repair (two errors).
    if((p1 && !(c01 && c11 && c21)) || (p2 && !(c02 && c12 && c22))) {
        return 0;
    }

    // h7, h5, h3, h1
    bitarray[7] = bitarray2[7];
    bitarray[6] = bitarray2[5];
    bitarray[5] = bitarray2[3];
    bitarray[4] = bitarray2[1];
    bitarray[3] = bitarray1[7];
    bitarray[2] = bitarray1[5];
    bitarray[1] = bitarray1[3];
    bitarray[0] = bitarray1[1];

    //     c0 c1 c2    meaning
    //     0  0  1    error in bit h7
    //     0  1  0    error in bit h5
    //     1  0  0    error in bit h3
    //     0  0  0    error in bit h1
    if(!p2) {
        if(!c02 && !c12 && c22)
            bitarray[7] = !bitarray[7];
        if(!c02 && c12 && !c22)
            bitarray[6] = !bitarray[6];
        if(c02 && !c12 && !c22)
            bitarray[5] = !bitarray[5];
        if(!c02 && !c12 && !c22)
            bitarray[4] = !bitarray[4];
        printf("Bit fixed in bitarray2\n");
    }
    if(!p1) {
        if(!c01 && !c11 && c21)
            bitarray[3] = !bitarray[3];
        if(!c01 && c11 && !c21)
            bitarray[2] = !bitarray[2];
        if(c01 && !c11 && !c21)
            bitarray[1] = !bitarray[1];
        if(!c01 && !c11 && !c21)
            bitarray[0] = !bitarray[0];
        printf("Bit fixed in bitarray1\n");
    }

    *number = bin2char(bitarray);
    return 1;
}
